package s;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import javax.imageio.ImageIO;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.mysql.jdbc.Statement;

import java.util.Properties;

import cbir.Field;
import cbir.Rss;
import cbir.ScaleJPG;
import cbir.Search;
import cbir.Thumb;
import cbir.Img;


public class QBN extends HttpServlet{
		
		private static final long serialVersionUID = 1L;
		
		private Properties props;
		private String propsPath;
		private static final int numResults = 20;

	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		
		this.propsPath = this.getServletContext().getRealPath("/");
		this.props = new Properties();
		try {
			props.loadFromXML(new FileInputStream(propsPath + "properties.properties"));
		} catch (FileNotFoundException e) {e.printStackTrace();} 
		catch (IOException e) {e.printStackTrace();}
}

			@Override
			protected void doPost(HttpServletRequest req, HttpServletResponse res)	throws ServletException, IOException {

				String pathToBeUsed;
				String filename = req.getParameter("imageURI");			
				
				String name;
				String thumb;	
					
				if(filename.indexOf("http://") != -1){
						
						pathToBeUsed = this.getServletContext().getRealPath("/") + props.getProperty("IMG_PATH_NOMEM") + "thumb/";
						URL url = new URL(filename);
				        BufferedImage image = ImageIO.read(url);
				        name = "name.jpg";
				        thumb = "thumb.jpg";
				        
				        File file = new File( this.getServletContext().getRealPath("/") + props.getProperty("IMG_PATH_NOMEM") + name);
				        
				        try{
				        	ImageIO.write(image, "JPG", file);
				        }
				        catch(IllegalArgumentException e){
				        	PrintWriter pw = res.getWriter();
				        	pw.write("FAIL");
				        	e.printStackTrace();
				        	return;
				        }

				        // Write the thumb
						ScaleJPG.scale( this.getServletContext().getRealPath("/") + props.getProperty("IMG_PATH_NOMEM"), this.getServletContext().getRealPath("/") + props.getProperty("IMG_PATH_NOMEM") + "thumb/", name, thumb);
						
				}
				else if(filename.indexOf("local://") != -1){
						name = filename.substring( filename.indexOf("local://")+8, filename.length() );
						thumb = Thumb.getThumb(name);
						pathToBeUsed =  this.getServletContext().getRealPath("/") + props.getProperty("IMG_PATH") + "thumb/";
				}
				else{
						PrintWriter pw = res.getWriter();
						pw.print("FAIL");
						return;
				}
					
					
				// Let's search!
				Search s = new Search(pathToBeUsed,  this.getServletContext().getRealPath("/") + props.getProperty("INDEX_PATH"));
				LinkedList<Field> listaColorHistogram =  s.searchWeighted(pathToBeUsed + thumb, 1.f, 0.f, 0.f);
				LinkedList<Field> listaColorDistribution =  s.searchWeighted(pathToBeUsed + thumb, 0.f, 1.f, 0.f);
				LinkedList<Field> listaTexture =  s.searchWeighted(pathToBeUsed + thumb, 0.f, 0.f, 1.f);
	
				// Merge colorHist and colorDist...
				ArrayList<Img> imgs = new ArrayList<Img>();
				ListIterator<Field> lit = listaColorHistogram.listIterator();
				boolean found = false;
				while(lit.hasNext()){
							Field c = lit.next();
							ListIterator<Field> lit2 = listaColorDistribution.listIterator();
							found = false;
							Img tmp = null;
							while(lit2.hasNext()  && found == false){
								Field c2 = lit2.next();
								if(c2.getName().compareTo( c.getName() ) == 0){
									tmp = new Img(c.getName(), req.getServerName(), req.getContextPath());
									tmp.setColorHistScore(c.getScore());
									tmp.setColorDistScore(c2.getScore());
									found = true;
								}
							}
							tmp.setColorScore();
							imgs.add(tmp);
				}
				// ...ok!
					
					
				// Merge color and texture...
				lit = listaTexture.listIterator();
					
				while(lit.hasNext()){
						Field c = lit.next();
						Iterator<Img> it = imgs.iterator();
						found = false;
						Img tmp  = null;
						while(it.hasNext() && found == false){
							tmp = it.next();
							if(tmp.getThumbname().compareTo( c.getName() ) == 0){
								tmp.setTextureScore(c.getScore());
								found = true;
							}
						}
						tmp.setSimilarityScore();
				}
				myOrder(imgs);
				// ...ok!
					
					
				if(imgs.size() == 0){
						PrintWriter out = res.getWriter();
						out.println("The database is empty: cannot search for similar images!");
//						System.out.println("The database is empty: cannot search for similar images!");
						return;
				}

				Connection connection = null;		
				Statement statement = null;
				
								
				/* ****************************************************** */
				// 
				int numResultsToBeShown = imgs.size() > numResults ? numResults+1 : imgs.size();
				//
				/* ****************************************************** */
				try {
					Class.forName("com.mysql.jdbc.Driver");
					connection= DriverManager.getConnection(props.getProperty("DB_URL"), props.getProperty("DB_USER"), props.getProperty("DB_PASS"));
					statement = (Statement) connection.createStatement();
						
						// Query
						String query = "SELECT Filename, Height, Width FROM img WHERE";
						for(int j = 0; j < numResultsToBeShown-1; j++){
							query = query.concat(" Filename = '" + imgs.get(j).getName() + "' OR");
						}
						query = query.concat(" Filename = '" + imgs.get(numResultsToBeShown-1).getName() + "';" );
						
						ResultSet rs = statement.executeQuery(query);
						rs = statement.executeQuery(query);
						
						while(rs.next()){
							String nameCurrent = rs.getString("Filename");	
							
							Iterator<Img> it = imgs.iterator();
							found = false;
							
							Img tmp = null;
							while(it.hasNext() && found == false){
									tmp = it.next();
	
									if(tmp.getName().compareTo(nameCurrent) == 0){
										tmp.setHeight(rs.getInt("Height"));
										tmp.setWidth(rs.getInt("Width"));
										// add tag
										statement = (Statement) connection.createStatement();
										ResultSet r = statement.executeQuery("SELECT tag.Tag as x FROM tag, imgTag WHERE tag.IdTag = imgTag.IdTag AND imgTag.IdImg = (SELECT img.IdImg FROM img WHERE img.Filename ='"+ tmp.getName() +"');");
										while(r.next())
											tmp.addTag(r.getString("x"));
										//
										found = true;
									}
							}
						}
	
					} catch (SQLException e1) {e1.printStackTrace();} catch (ClassNotFoundException e) {
						e.printStackTrace();
					}
					finally {
						try {connection.close();} 
						catch (SQLException e) {e.printStackTrace();}
					}
					
					if(imgs.get(0).getSimilarityScore() == 1.)
						imgs.remove(0);
					
					if(imgs.size() == 0)
						return;
					
					Rss r = new Rss(getServletName(), req.getServerName(), req.getContextPath());
					ArrayList<Img> truncated = new ArrayList<Img>(numResultsToBeShown-1);
					for(int h = 0; h < numResultsToBeShown-1; h++){
						imgs.get(h).setGlobalRank(imgs.indexOf(imgs.get(h)));
						truncated.add(imgs.get(h));
					}
					r.createRss(truncated);
					String rss = r.getRss();
					PrintWriter pw = res.getWriter();
					pw.print(rss);
			}	
			
			private void myOrder(ArrayList<Img> x) {
				Collections.sort(x, new Comparator<Img>(){
					@Override
					public int compare(Img a, Img b) {
						if(a.getSimilarityScore() < b.getSimilarityScore())
							return +1;
						else if (a.getSimilarityScore() == b.getSimilarityScore())
							return 0;
						else
							return -1;
					}
				});
				
			}			
}